#include "simple.h"
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>



int elog_sp_power(int num, int exp)
{
	/*    if (exp == 0)
	   return 1;
	   int c;
	   int res = 1;
	   for (c=0; c < exp; ++c)
	   res = res*num; */

	//return res;
	//^^^ leave above code, I'm not sure which is faster.

	return (int) powf((float) num, (float) exp);
}

int elog_sp_stringToShort(const char *str)
{
	int x = 0;
	int len = strlen(str) - 1;
	int c;
	for (c = 0; str[c] != '\0'; ++c)
		x += (str[c] - '0') * elog_sp_power(10, len - c);
	return x;
}

char *elog_sp_whiteSpaceRemove(const char *str)
{
	if (str == NULL)
		return NULL;
	int c;
	for (c = 0; str[c] != '\0' && (str[c] == ' ' || str[c] == '	'
				       || str[c] == '\n'); ++c);
	//^^empty loop, just finds our real beginning point.


	//char *x = new char[strlen(str)-c+1];
	int j;
	for (j = strlen(str) - 1;
	     j > c && (str[j] == ' ' || str[j] == '	'
		       || str[j] == '\n'); --j);
	//^^empty loop, finds last non-white char
	++j;

	if (c == j)
		return NULL;
	//^^this means it's all whitespace

	char *x;
	x = malloc((sizeof *x) * (j - c + 1));
	strncpy(x, &(str[c]), j - c);

	x[j - c] = '\0';
	return x;
}
char *elog_sp_toChar(unsigned char *in, unsigned int len)
{
	/*    char *ans; ans = malloc((sizeof *ans)*(len+1));
	   ans[len] = '\0';
	   int c;
	   for (c=0; c < len; ++c)
	   ans[c] = in[c];
	   return ans; */
	return (char *) in;
}

unsigned char *elog_sp_toUnsignedChar(char *in, unsigned int *len)
{
	/*   *len = strlen(in);
	   unsigned char *ans; ans = malloc((sizeof *ans)*(*len+1));
	   int c;
	   for (c=0; c < *len; ++c)
	   ans[c] = in[c];     
	   return ans; */
	*len = strlen(in) + 1;
	return (unsigned char *) in;
}

char *elog_sp_shortToString(int num)
{
	int c;
	for (c = 1; elog_sp_power(10, c) <= num; ++c);
	//^^counting places
	char *ans;
	ans = malloc((sizeof *ans) * (c + 1));
	ans[c] = '\0';

	int j;
	for (j = c; j > 0; --j) {
		int x = elog_sp_power(10, j - 1);
		ans[c - j] = num / x + '0';
		num = num % x;
	}
	return ans;
}
const char *elog_sp_lastSameChar(const char *str, char ch)
//say str = "//abc" and ch = '/', then /abc is returned
{
	if (str == NULL)
		return NULL;
	int c;
	for (c = 0; str[c + 1] != '\0' && str[c + 1] == ch; ++c);
	if (str[c] == '\0')
		return str;
	return &(str[c]);
}
char **elog_sp_breakToArr(const char *fileName, char seperator)
{

	char **path;
	const char *i = fileName;
	int cells = 0;
	while ((i = strchr(i, seperator)) != NULL) {
		++cells;
		i = &(elog_sp_lastSameChar(i, seperator)[1]);
	}
	path = malloc((sizeof *path) * (cells + 2));

	i = fileName;
	int c;
	for (c = 0; c < cells; ++c) {
		char *i_1 = strchr(i, seperator);	//end of cell.
		if (i_1 == NULL)
			break;	//end loop, shouldn't happen
		path[c] = malloc((sizeof *path[0]) * (i_1 - i + 1));
		strncpy(path[c], i, (i_1 - i) / (sizeof *i));
		path[c][i_1 - i] = '\0';
		i = &(elog_sp_lastSameChar(i_1, seperator)[1]);
	}
	path[cells] = malloc((sizeof *path[0]) * (strlen(i) + 1));
	path[cells][0] = '\0';
	strcpy(path[cells], i);

	path[cells + 1] = NULL;

	char *last_cell = elog_sp_whiteSpaceRemove(path[cells]);
	if (last_cell == NULL) {
		free(path[cells]);
		path[cells] = NULL;
	}			//checking if the last cell is blank.
	else
		free(last_cell);

	return path;
}
void elog_sp_ArrFree(char **arr)
{
	int c;
	for (c = 0; arr[c] != NULL; ++c)
		free(arr[c]);
	free(arr);
}

/*The following is a speed hack, it takes repetitive
 * strcat's from O(n^2) to O(n)	*/
char *__cat(char *dest, const char *x)
{
	while (*dest)
		dest++;
	while ((*dest++ = *x++));	//apparently this works?
	return --dest;
}

void elog_sp_cat(char **template, ...)
{
	struct list {
		char *str;
		struct list *next;
	};

	struct list *strings = malloc((sizeof *strings));
	struct list *p = strings;
	int total_size = 0;
	char *final;
	va_list ap;

	va_start(ap, template);
	char *c;
	while ((c = va_arg(ap, char *)) != NULL) {
		total_size += strlen(c);
		p->next = malloc(sizeof *strings);
		p->str = c;
		p = p->next;
		p->next = NULL;
	}
	*template = final = malloc((sizeof *final) * (total_size + 1));
	final[0] = '\0';
	p = strings;
	while (p->next != NULL) {
		final = __cat(final, p->str);
		strings = p;
		p = p->next;
		free(strings);
	}
	free(p);
	va_end(ap);
}

char *elog_sp_cpy_str(const char *str)
{
	if (str == NULL)
		return elog_sp_cpy_str("(NULL)");
	char *ret = malloc((sizeof *ret) * (strlen(str)+1));
	ret[0] = '\0';
	__cat(ret, str);
	return ret;	
}
int *elog_sp_heap_int(int n)
{
	int *ret = malloc(sizeof *ret);
	*ret = n;
	return ret;	
}

char *elog_sp_strReplace(const char *str, const char *old, const char *new)
{
	int len = strlen(str);
	int occur[1024 * 16];
	int c = 0;
	const char *p = str;
	while ((p = strstr(p, old)) != NULL) {
		occur[c] = (p - str) / (sizeof *p);
		++p;
		++c;
	}

	occur[c] = -1;		//stop condition
	int len_o = strlen(old);
	int len_n = strlen(new);
	int diff = (len_n - len_o) * c;

	char *nue = malloc((sizeof *old) * (len + diff + 1));
	nue[0] = '\0';
	c = 0;
	int j = 0;
	int i = 0;
	for (j = 0; j < len; ++j) {
		if (occur[c] + 1) {
			if (j == occur[c]) {
				strcpy(&(nue[i]), new);
				i += len_n;
				j += len_o - 1;
				++c;
			} else {
				nue[i] = str[j];
				++i;
			}
		} else {
			nue[i] = str[j];
			++i;
		}
	}
	nue[i] = '\0';
	return nue;
}

float elog_sp_stringToFloat(char *str)
{
	/*char *str_c;
	   elog_sp_cat(&str_c, str, NULL);

	   char *dot = strchr(str_c, '.');
	   int point = (str_c - dot)/(sizeof *dot);
	   int c;
	   for (c=point; str_c[c] != '\0'; ++c)
	   str_c[c] = str_c[c+1];
	   //moving over the stuff from the dot.
	   point = strlen(str) - point; //index from the right
	   float result = (float)elog_sp_stringToShort(str_c);
	   result = result / pow(10, point); */

	return (float) atof(str);
}
void elog_sp_resizeArray(char ***array)
{
	int size;
	for (size = 0; (*array)[size] != NULL; ++size);	//intentional

	int nue_size = size * 2;
	char **nue_arr = malloc((sizeof *array) * (nue_size + 1));
	int c;
	for (c = 0; c < size; ++c)
		nue_arr[c] = (*array)[c];
	for (; c <= nue_size; ++c)
		nue_arr[c] = NULL;
	free(*array);
	*array = nue_arr;
}
void elog_sp_resizeArrayWSize(char ***array, int *size)
{
	int nue_size = (*size) * 2;
	char **nue_arr = malloc((sizeof *array) * (nue_size + 1));
	int c;
	for (c = 0; c < *size; ++c)
		nue_arr[c] = (*array)[c];
	for (; c <= nue_size; ++c)
		nue_arr[c] = NULL;
	free(*array);
	*size = nue_size;
	*array = nue_arr;
}
void elog_sp_resizeArrayInt(int **array, int *size)
{
	int nue_size = (*size) * 2;
	int *nue_arr = malloc((sizeof *array) * (nue_size + 1));
	int c;
	for (c = 0; c < *size; ++c)
		nue_arr[c] = (*array)[c];
	for (; c <= nue_size; ++c)
		nue_arr[c] = -1;
	free(*array);
	*size = nue_size;
	*array = nue_arr;
}
char *elog_sp_getLine(const char *data, int line)
{
	const char *loc = data;
	int c;
	for (c = 0; c < line; ++c) {
		loc = &(strchr(loc, '\n')[1]);
		if (loc == NULL)
			return NULL;
	}
	if (loc - data >= strlen(data))
		return NULL;
	const char *end = strchr(loc + 1, '\n');

	if (end == NULL)
		end = &(loc[strlen(loc) - 1]);
	if (loc == NULL || end == NULL)
		return NULL;


	char *ret = malloc((sizeof *ret) * (end - loc + 1));
	strncpy(ret, loc, (sizeof *loc) * (end - loc));
	ret[end - loc] = '\0';
	return ret;
}

int elog_sp_removeRepeats(char *str, char item)
{
	int c;
	int diff = 0;
	int occur = 0;
	for (c = 0; str[c] != '\0'; ++c) {
		str[c - diff] = str[c];

		if (str[c] == item)
			++occur;
		else
			occur = 0;

		if (occur > 1)
			++diff;
	}

	str[c - diff] = '\0';
	return 0;
}
